package com.zhongjh.imageingstudy.view.image;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.Log;

import androidx.annotation.ColorInt;

import com.zhongjh.imageingstudy.core.ImageMode;
import com.zhongjh.imageingstudy.util.ImageUtils;
import com.zhongjh.imageingstudy.homing.ImageHoming;
import com.zhongjh.imageingstudy.view.clip.ImageClip;
import com.zhongjh.imageingstudy.view.clip.ImageClipView;

public class ActionImage {

    private final String TAG = ActionImage.class.getSimpleName();
    private final static float SCALE_MAX = 1f;
    /**
     * 宽高最小值
     */
    private static final int MIN_SIZE = 500;
    /**
     * 宽高最打值
     */
    private static final int MAX_SIZE = 10000;

    /**
     * 原图
     */
    Bitmap mOriginBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
    /**
     * 用于处理缩放、旋转等操作
     */
    public final Matrix mMatrix = new Matrix();
    /**
     * 整个大窗口
     */
    public final RectF mWindow = new RectF();
    /**
     * 完整图片边框
     */
    public final RectF mFrame = new RectF();
    /**
     * 裁剪边框:裁剪后,最终经过各种计算最终形成的新的裁剪框
     */
    public final RectF mClipFrame = new RectF();
    /**
     * 裁剪View
     */
    public final ImageClipView mImageClipView = new ImageClipView();

    /**
     * 裁剪模式时当前触摸锚点
     */
    private ImageClip.Anchor mAnchor;
    private final Path mShade = new Path();

    private final Paint mShadePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    /**
     * 编辑模式
     */
    private ImageMode mMode = ImageMode.NONE;
    /**
     * 旋转角度
     */
    private float mRotate = 0, mTargetRotate = 0;
    /**
     * 是否初始化完成
     */
    private boolean isInitialHoming = false;
    /**
     * 图片是否稳定，例如没有正在动画中
     */
    private boolean mIsSteady = true;
    /**
     * 动画是否取消
     */
    private boolean mIsAnimCanceled = false;

    {
        mShade.setFillType(Path.FillType.WINDING);

        mShadePaint.setColor(0xCC000000);
        mShadePaint.setStyle(Paint.Style.FILL);
    }

    /**
     * 设置图片数据源
     */
    public void setBitmap(Bitmap bitmap) {
        if (bitmap == null || bitmap.isRecycled()) {
            return;
        }
        mOriginBitmap = bitmap;
        mFrame.set(0, 0, mOriginBitmap.getWidth(), mOriginBitmap.getHeight());
        mClipFrame.set(mFrame);
        Log.d(TAG, "setBitmap width: " + mOriginBitmap.getWidth() + " height: " + mOriginBitmap.getHeight());
    }

    /**
     * 绘制图片
     *
     * @param canvas 绘制类
     */
    public void onDrawImage(Canvas canvas) {
//        onDrawLine(canvas, mFrame, Color.RED);
        onDrawLine(canvas, mClipFrame, Color.RED);
//        onDrawLine(canvas, mWindow, Color.RED);
        // 在mFrame该边框绘制图片
        canvas.drawBitmap(mOriginBitmap, null, mFrame, null);
    }

    /**
     * 绘制参考线,开发用
     */
    private void onDrawLine(Canvas canvas, RectF frame, @ColorInt int color) {
        Paint paint = new Paint();
        paint.setColor(color);//颜色
        paint.setStrokeWidth(3);//线宽
        int verNum = (int) ((frame.bottom - frame.top) / 100) + 1;
        int horNum = (int) ((frame.right - frame.left) / 100) + 1;
        // 画横线
        for (int i = 0; i < verNum; i++) {
            canvas.drawLine(frame.left, frame.top + (i * 100 - 1), frame.right, frame.top + (i * 100 - 1), paint);
        }
        // 画竖线
        for (int i = 0; i < horNum; i++) {
            canvas.drawLine(frame.left + (i * 100 - 1), frame.top, frame.left + (i * 100 - 1), frame.bottom, paint);
        }
    }

    /**
     * 绘制遮罩层,当裁剪框小于图片,这个交叉区域就是遮罩层
     *
     * @param canvas 绘制类
     */
    public void onDrawShade(Canvas canvas) {
        Log.d(TAG, "onDrawShade");
        if (mMode == ImageMode.CLIP && isSteady()) {
            mShade.reset();
            // addRect添加两个层次
            mShade.addRect(mFrame.left - 2, mFrame.top - 2, mFrame.right + 2, mFrame.bottom + 2, Path.Direction.CW);
            // Path.Direction.CCW逆时针，即是绘制内层
            mShade.addRect(mClipFrame, Path.Direction.CCW);
            // mShadePaint遮罩层画笔进行绘制
            canvas.drawPath(mShade, mShadePaint);
        }
    }

    public ImageMode getMode() {
        return mMode;
    }

    /**
     * 设置模式
     *
     * @param mode 模式类
     */
    public void setMode(ImageMode mode) {
        if (this.mMode == mode) {
            return;
        }
        this.mMode = mode;

        if (mMode == ImageMode.CLIP) {
            float scale = 1 / getScale();
            mMatrix.setTranslate(-mFrame.left, -mFrame.top);
            mMatrix.postScale(scale, scale);

            // 重置裁剪区域
            mImageClipView.reset(mClipFrame, getTargetRotate());
        }
    }

    /**
     * 改变布局大小时触发
     * 会比setBitmap先触发,同时invalidate不会触发执行onLayout
     *
     * @param width  宽度
     * @param height 高度
     */
    public void onLayout(float width, float height) {
        Log.d(TAG, "onLayout");
        if (width == 0 || height == 0) {
            return;
        }

        mWindow.set(0, 0, width, height);

        if (!isInitialHoming) {
            onInitialHoming(width, height);
        } else {
            mMatrix.setTranslate(mWindow.centerX() - this.mClipFrame.centerX(), mWindow.centerY() - this.mClipFrame.centerY());
            mMatrix.mapRect(mFrame);
            mMatrix.mapRect(this.mClipFrame);
        }

        // 计算裁剪窗口区域
        mImageClipView.setClipWinSize(width, height);
    }

    /**
     * 裁剪区域旋转回原始角度后形成新的裁剪区域，旋转中心发生变化，
     * 因此需要将视图窗口平移到新的旋转中心位置。
     */
    public ImageHoming clip(float scrollX, float scrollY) {
        Log.d(TAG, "clip");
        RectF frame = mImageClipView.getOffsetFrame(scrollX, scrollY);

        mMatrix.setRotate(-getRotate(), this.mClipFrame.centerX(), this.mClipFrame.centerY());
        // 将frame的四角值赋值给mClipFrame
        mMatrix.mapRect(this.mClipFrame, frame);

        return new ImageHoming(
                scrollX + (this.mClipFrame.centerX() - frame.centerX()),
                scrollY + (this.mClipFrame.centerY() - frame.centerY()),
                getScale(), getRotate()
        );
    }

    public void onHomingStart() {
        Log.d(TAG, "onHomingStart");
        mIsAnimCanceled = false;
    }

    public void onHomingCancel(boolean isRotate) {
        Log.d(TAG, "onHomingCancel");
        mIsAnimCanceled = true;
    }

    public void onHoming(float fraction) {
        Log.d(TAG, "onHoming");
        mImageClipView.homing(fraction);
    }

    /***
     * 归位结束
     * @param scrollX 滑动x轴
     * @param scrollY 滑动y轴
     * @param isRotate 是否旋转
     * @return 是否结束
     */
    public boolean onHomingEnd(float scrollX, float scrollY, boolean isRotate) {
        Log.d(TAG, "onHomingEnd");
        if (mMode == ImageMode.CLIP) {
            // 裁剪模式
            boolean clip = !mIsAnimCanceled;
            mImageClipView.setHoming(false);
            mImageClipView.setClipping(true);
            mImageClipView.setResetting(false);
            return clip;
        }
        return false;
    }

    /**
     * 初始化设置 mFrame、mImageClipView区域的宽高
     *
     * @param width  宽度
     * @param height 高度
     */
    private void onInitialHoming(float width, float height) {
        Log.d(TAG, "onInitialHoming width " + width + " originWidth: " + mOriginBitmap.getWidth() + " height:" + height + " originHeight: " + mOriginBitmap.getHeight());
        mFrame.set(0, 0, mOriginBitmap.getWidth(), mOriginBitmap.getHeight());
        mClipFrame.set(mFrame);
        // 设置裁剪区域的宽高
        mImageClipView.setClipWinSize(width, height);

        if (this.mClipFrame.isEmpty()) {
            return;
        }
        toBaseHoming();
        isInitialHoming = true;
        onInitialHomingDone();
    }

    private void toBaseHoming() {
        Log.d(TAG, "toBaseHoming");
        if (mClipFrame.isEmpty()) {
            // Bitmap invalidate.
            return;
        }

        float scale = Math.min(
                mWindow.width() / mClipFrame.width(),
                mWindow.height() / mClipFrame.height()
        );

        // Scale to fit window.
        mMatrix.setScale(scale, scale, mClipFrame.centerX(), mClipFrame.centerY());
        mMatrix.postTranslate(mWindow.centerX() - mClipFrame.centerX(), mWindow.centerY() - mClipFrame.centerY());
        mMatrix.mapRect(mFrame);
        mMatrix.mapRect(mClipFrame);
    }

    private void onInitialHomingDone() {
        Log.d(TAG, "onInitialHomingDone");
        if (mMode == ImageMode.CLIP) {
            mImageClipView.reset(mClipFrame, getTargetRotate());
        }
    }

    /**
     * 绘画裁剪
     *
     * @param canvas  绘画工具
     * @param scrollX 滑动x轴
     * @param scrollY 滑动y轴
     */
    public void onDrawClip(Canvas canvas, float scrollX, float scrollY) {
        Log.d(TAG, "onDrawClip");
        if (mMode == ImageMode.CLIP) {
            mImageClipView.onDraw(canvas);
        }
    }

    /**
     * 触屏按下事件触发
     *
     * @param x x轴
     * @param y y轴
     */
    public void onTouchDown(float x, float y) {
        Log.d(TAG, "onTouchDown");
        setSteady(false);
        if (mMode == ImageMode.CLIP) {
            mAnchor = mImageClipView.getAnchor(x, y);
        }
    }

    /**
     * 触屏松开事件触发
     *
     * @param scrollX 滑动x轴
     * @param scrollY 滑动y轴
     */
    public void onTouchUp(float scrollX, float scrollY) {
        Log.d(TAG, "onTouchUp");
        setSteady(true);
        if (mAnchor != null) {
            mAnchor = null;
        }
    }

    /**
     * 滑动事件
     *
     * @param scrollX 当前手指的x轴
     * @param scrollY 当前手指的y轴
     * @param dx      手指在x轴上的移动
     * @param dy      手指在y轴上的移动
     */
    public void onScroll(float scrollX, float scrollY, float dx, float dy) {
        Log.d(TAG, "onScroll");
        if (mMode == ImageMode.CLIP) {
            if (mAnchor != null) {
                mImageClipView.onScroll(mAnchor, dx, dy);

                RectF clipFrame = new RectF();
                mMatrix.setRotate(getRotate(), mClipFrame.centerX(), mClipFrame.centerY());
                mMatrix.mapRect(clipFrame, mFrame);
            }
        }
    }

    /**
     * 设置裁剪的归位目标区域
     */
    public void setClipHomingFrame() {
        Log.d(TAG, "onClipHoming");
        setSteady(true);
        mImageClipView.setHomingFrame();
    }

    /**
     * 获取当前图片的相关属性,辅助归位功能
     *
     * @param scrollX 控件在窗口左边界X轴的值
     * @param scrollY 控件在窗口左边界Y轴的值
     * @return 当前图片属性
     */
    public ImageHoming getStartHoming(float scrollX, float scrollY) {
        Log.d(TAG, "getStartHoming: scrollX(" + scrollX + ") scrollY(" + scrollY + ") getScale(" + getScale() + ") getRotate(" + getRotate() + ")");
        return new ImageHoming(scrollX, scrollY, getScale(), getRotate());
    }

    /**
     * 获取归位后图片的相关属性,辅助归位功能
     *
     * @param scrollX 控件在窗口左边界X轴的值
     * @param scrollY 控件在窗口左边界Y轴的值
     * @return 归位后的图片属性
     */
    public ImageHoming getEndHoming(float scrollX, float scrollY) {
        // 当前的homing
        ImageHoming homing = new ImageHoming(scrollX, scrollY, getScale(), getTargetRotate());
        if (mMode == ImageMode.CLIP) {
            // 归位frame
            RectF homingFrame = new RectF(mImageClipView.getHomingFrame());
            // 移动frame
            homingFrame.offset(scrollX, scrollY);
            if (mImageClipView.isResetting()) {
                // 如果正在重置中
                RectF clipFrame = new RectF();
                mMatrix.setRotate(getTargetRotate(), mClipFrame.centerX(), mClipFrame.centerY());
                mMatrix.mapRect(clipFrame, mClipFrame);
                homing.rConcat(ImageUtils.fill(homingFrame, clipFrame));
            } else if (mImageClipView.isHoming()) {
                // 如果正在归位中
                RectF cFrame = new RectF();
                mMatrix.setRotate(getTargetRotate() - getRotate(), mClipFrame.centerX(), mClipFrame.centerY());
                // 挪动裁剪的Frame
                RectF rectF = mImageClipView.getOffsetFrame(scrollX, scrollY);
                mMatrix.mapRect(cFrame, rectF);
                homing.rConcat(ImageUtils.fitHoming(homingFrame, cFrame, mClipFrame.centerX(), mClipFrame.centerY()));
            } else {
                // 其他模式
                RectF imageFrame = new RectF();
                mMatrix.setRotate(getTargetRotate(), mClipFrame.centerX(), mClipFrame.centerY());
                mMatrix.mapRect(imageFrame, mFrame);
                homing.rConcat(ImageUtils.fillHoming(homingFrame, imageFrame, mClipFrame.centerX(), mClipFrame.centerY()));
            }
        }
        return homing;
    }

    public void onScale(float factor, float focusX, float focusY) {
        Log.d(TAG, "onScale");

        if (Math.abs(factor) == Math.abs(SCALE_MAX)) {
            return;
        }

        if (Math.max(mClipFrame.width(), mClipFrame.height()) >= MAX_SIZE
                || Math.min(mClipFrame.width(), mClipFrame.height()) <= MIN_SIZE) {
            factor += (1 - factor) / 2;
        }

        mMatrix.setScale(factor, factor, focusX, focusY);
        mMatrix.mapRect(mFrame);
        mMatrix.mapRect(mClipFrame);

//        // 缩放贴片
//        for (ImageSticker sticker : mBackStickers) {
//            mMatrix.mapRect(sticker.getFrame());
//            float tPivotX = sticker.getX() + sticker.getPivotX();
//            float tPivotY = sticker.getY() + sticker.getPivotY();
//            sticker.addScale(factor);
//            sticker.setX(sticker.getX() + sticker.getFrame().centerX() - tPivotX);
//            sticker.setY(sticker.getY() + sticker.getFrame().centerY() - tPivotY);
//        }
    }


    public float getTargetRotate() {
        Log.d(TAG, "getTargetRotate");
        return mTargetRotate;
    }

    public void setTargetRotate(float targetRotate) {
        Log.d(TAG, "setTargetRotate");
        this.mTargetRotate = targetRotate;
    }

    public float getRotate() {
        Log.d(TAG, "getRotate");
        return mRotate;
    }

    public void setRotate(float rotate) {
        Log.d(TAG, "setRotate");
        mRotate = rotate;
    }

    /**
     * view缩放后的宽度 / 图片固定宽度 = 缩放比例
     */
    public float getScale() {
        Log.d(TAG, "getScale");
        return mFrame.width() / mOriginBitmap.getWidth();
    }

    public void setScale(float scale) {
        Log.d(TAG, "setScale");
        onScale(scale / getScale(), mClipFrame.centerX(), mClipFrame.centerY());
    }

    public boolean isSteady() {
        return mIsSteady;
    }

    public void setSteady(boolean isSteady) {
        this.mIsSteady = isSteady;
    }
}
